#ifndef TIGER_PARSE_PARSER_H_
#define TIGER_PARSE_PARSER_H_

#include <iostream>
#include <list>

#include "tiger/lex/scanner.h"
#include "tiger/parse/parserbase.h"
#include "tiger/symbol/symbol.h"

#undef Parser

class Parser : public ParserBase {
public:
  Parser() = delete;
  Parser(std::string_view fname, std::ostream &out) : scanner_(fname, out) {}

  /**
   * Transfer the ownership of absyn tree to outer scope
   * @return unique pointer to the absyn tree
   */
  std::unique_ptr<absyn::AbsynTree> TransferAbsynTree() {
    return std::move(absyn_tree_);
  }

  /**
   * Transfer the ownership of errormsg to outer scope
   * @return unique pointer to errormsg
   */
  std::unique_ptr<err::ErrorMsg> TransferErrormsg() {
    return std::move(scanner_.TransferErrormsg());
  }

  /**
   * NOTE: Implementation is autogenerated by bisonc++, do not edit this
   * declaration.
   */
  int parse();

private:
  Scanner scanner_;
  std::unique_ptr<absyn::AbsynTree> absyn_tree_;
  std::list<std::string> string_pool_;

  /**
   * NOTE: Following methods are used by bisonc++, do not change
   * them
   */
  void error();
  int lex();
  void print();
  void exceptionHandler(std::exception const &exc);

  void executeAction__(int ruleNr);
  void errorRecovery__();
  void nextCycle__();
  void nextToken__();
  void print__();
};

inline void Parser::error() {
  scanner_.Error(scanner_.GetTokPos(), "syntax error");
  exit(1);
}

inline int Parser::lex() {
  int token = scanner_.lex();
  switch (token) {
  case Parser::ID:
    d_val__.sym = sym::Symbol::UniqueSymbol(scanner_.matched());
    break;
  case Parser::STRING:
    string_pool_.push_back(scanner_.matched());
    d_val__.sval = &string_pool_.back();
    break;
  case Parser::INT:
    d_val__.ival = std::stoi(scanner_.matched());
    break;
  default:
    break;
  }
  return token;
}

inline void Parser::print() { print__(); }

inline void Parser::exceptionHandler(std::exception const &exc) { throw; }

#endif // TIGER_PARSE_PARSER_H_
